package com.stackexchange.webapis.methodgroups
{
	import com.stackexchange.webapis.client.StackExchangeService;
	import com.stackexchange.webapis.stackexchangeservice_internal;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;

	use namespace stackexchangeservice_internal;

	/**
	 * Method caller is in charge of building the query and 
	 * makes the call to the RPC
	 **/
	public class MethodCaller
	{
		/**
		 * Reusable method that the "method group" classes can call to invoke a
		 * method on the API.
		 *
		 * @param The service containing the API key
		 * @param methodName The name of the method to invoke
		 * @param callback The function to be notified when the RPC is complete
		 * @param tokens An index collection of values that will replace the query tokens
		 * @param params An index collection of values to be passes as parameters to the remote method
		 */
		public function call(service:StackExchangeService, 
							 methodName:String,
							 callback:Function,
							 tokens:Object,
							 parameters:Object):void
		{
			var parameters:Object = addKeyToParameters(parameters, service.apiKey);
			var query:String = constructQuery(methodName, tokens, parameters);
			
			callMethod(service, query, callback);
		}
		
		private function addKeyToParameters(parameters:Object, apiKey:String):Object
		{
			if (!parameters)
				parameters = {};
			
			parameters["key"] = apiKey;
			
			return parameters;
		}
		
		private function constructQuery(methodName:String, tokens:Object, parameters:Object):String
		{
			var query:String = replaceTokens(methodName, tokens);
			query = addParametersToQuery(query, parameters);
			
			return query;
		}
		
		private function replaceTokens(methodName:String, tokens:Object):String
		{
			for (var o:Object in tokens)
			{
				var value:String = "";
				
				if (tokens[o] is Array)
					value = getVectorizedToken(tokens[o] as Array);
				else
					value = tokens[o];
				
				methodName = methodName.replace("{"+o+"}", value);
			}
			
			return methodName;
		}
		
		private function getVectorizedToken(params:Array):String
		{
			var value:String = "";
			
			for (var i:int = 0; i < params.length; i++)
			{
				value += params[i];
				if (i < params.length-1)
					value += ";";
			}
			
			return value;
		}
		
		private function addParametersToQuery(query:String, parameters:Object):String
		{
			var parametersString:String = "?";
			var existingParams:Boolean = false;
			
			for (var o:Object in parameters)
			{
				existingParams = true;
				parametersString += o + "=" + parameters[o];
				parametersString += "&";
			}
			
			if (existingParams)
				parametersString = parametersString.slice(0, parametersString.length-1);
			
			return query+parametersString;
		}
			
		
		private function callMethod(service:StackExchangeService, query:String, callback:Function):void
		{
			var loader:URLLoader = service.stackexchangeservice_internal::urlLoader;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, service.dispatchError);
			
			loader.load(new URLRequest(StackExchangeService.END_POINT+ "/" + StackExchangeService.VERSION + "/" +query));
		}
	}
}